////////////////////////////////////////////////////////////////////////////////
// Filename: modelclass.cpp
////////////////////////////////////////////////////////////////////////////////
#include "modelclass.h"


ModelClass::ModelClass()
{
	m_vertexBuffer = 0;
	m_indexBuffer = 0;
}


ModelClass::ModelClass(const ModelClass& other)
{
}


ModelClass::~ModelClass()
{
}


bool ModelClass::Initialize(ID3D11Device* device)
{
	bool result;


	// Initialize the vertex and index buffers.
	result = InitializeBuffers(device);
	if(!result)
	{
		return false;
	}

	return true;
}


void ModelClass::Shutdown()
{
	for(iter = ModelList.begin(); iter < ModelList.end(); iter++)
	{
		delete (*iter);
	}
	// Shutdown the vertex and index buffers.
	ShutdownBuffers();
	
	return;
}


void ModelClass::Render(ID3D11DeviceContext* deviceContext, unsigned long runtime)
{
	Frame(runtime);
	UpdateBuffers(deviceContext);
	// Put the vertex and index buffers on the graphics pipeline to prepare them for drawing.
	RenderBuffers(deviceContext);

	return;
}


int ModelClass::GetIndexCount()
{
	return m_indexCount;
}



bool ModelClass::InitializeBuffers(ID3D11Device* device)
{

	if(!LoadData())
	{
		return false;
	}

	//GraphicsModel Rectangle("Rectangle.txt");
	unsigned long* indices;
	GraphicsModel::VertexType* vertices;
	D3D11_BUFFER_DESC indexBufferDesc;
    D3D11_SUBRESOURCE_DATA indexData;
	HRESULT result;

	// Set the number of vertices in the vertex array.
	m_vertexCount = 0;
	m_indexCount = 0;
	for(iter = ModelList.begin(); iter < ModelList.end(); iter++)
	{
		m_vertexCount += (*iter) -> vertexCount;
		m_indexCount += (*iter) -> indexCount;
	}

	// Create the vertex array.
	vertices = new GraphicsModel::VertexType[m_vertexCount];
	if(!vertices)
	{
		return false;
	}

	// Create the index array.
	indices = new unsigned long[m_indexCount];
	if(!indices)
	{
		return false;
	}

	// Load the vertex array with data.
	currentVertex = 0;
	currentIndex = 0;

	for(iter = ModelList.begin(); iter < ModelList.end(); iter++)
	{
		for(int j = 0; j < (*iter) -> indexCount; j++)
		{
			indices[currentIndex] = (*iter) -> Indices[j]+currentVertex;
			currentIndex++;
		}
		for(int j = 0; j < (*iter) -> vertexCount; j++)
		{
			vertices[currentVertex] = (*iter) -> Vertices[j];
			currentVertex++;
		}		
	}

	// Set up the description of the static vertex buffer.
    vertexBufferDesc.Usage = D3D11_USAGE_DYNAMIC;
    vertexBufferDesc.ByteWidth = sizeof(GraphicsModel::VertexType) * m_vertexCount;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
    vertexBufferDesc.MiscFlags = 0;
	vertexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the vertex data.
    vertexData.pSysMem = vertices;
	vertexData.SysMemPitch = 0;
	vertexData.SysMemSlicePitch = 0;

	// Now create the vertex buffer.
    result = device->CreateBuffer(&vertexBufferDesc, &vertexData, &m_vertexBuffer);
	if(FAILED(result))
	{
		return false;
	}

	// Set up the description of the static index buffer.
    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(unsigned long) * m_indexCount;
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;
	indexBufferDesc.StructureByteStride = 0;

	// Give the subresource structure a pointer to the index data.
    indexData.pSysMem = indices;
	indexData.SysMemPitch = 0;
	indexData.SysMemSlicePitch = 0;

	// Create the index buffer.
	result = device->CreateBuffer(&indexBufferDesc, &indexData, &m_indexBuffer);
	if(FAILED(result))
	{
		return false;
	}

	// Release the arrays now that the vertex and index buffers have been created and loaded.
	delete [] vertices;
	vertices = 0;

	delete [] indices;
	indices = 0;
	
	return true;
}

bool ModelClass::UpdateBuffers(ID3D11DeviceContext* deviceContext)
{
	GraphicsModel::VertexType* vertices;
	D3D11_MAPPED_SUBRESOURCE mappedResource;
	GraphicsModel::VertexType* verticesPtr;
	HRESULT result;

	vertices = new GraphicsModel::VertexType[m_vertexCount];
	if(!vertices)
	{
		return false;
	}

	// Load the vertex array with data.
	currentVertex = 0;

	for(iter = ModelList.begin(); iter < ModelList.end(); iter++)
	{
		for(int j = 0; j < (*iter) -> vertexCount; j++)
		{
			vertices[currentVertex] = (*iter) -> Vertices[j];
			currentVertex++;
		}		
	}

	result = deviceContext->Map(m_vertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &mappedResource);
	if(FAILED(result))
	{
		return false;
	}

	// Get a pointer to the data in the vertex buffer.
	verticesPtr = (GraphicsModel::VertexType*)mappedResource.pData;

	// Copy the data into the vertex buffer.
	memcpy(verticesPtr, (void*)vertices, (sizeof(GraphicsModel::VertexType) * m_vertexCount));

	// Unlock the vertex buffer.
	deviceContext->Unmap(m_vertexBuffer, 0);

	delete [] vertices;
	vertices = 0;

	return true;
}

void ModelClass::ShutdownBuffers()
{
	// Release the index buffer.
	if(m_indexBuffer)
	{
		m_indexBuffer->Release();
		m_indexBuffer = 0;
	}

	// Release the vertex buffer.
	if(m_vertexBuffer)
	{
		m_vertexBuffer->Release();
		m_vertexBuffer = 0;
	}

	return;
}


void ModelClass::RenderBuffers(ID3D11DeviceContext* deviceContext)
{
	unsigned int stride;
	unsigned int offset;


	// Set vertex buffer stride and offset.
	stride = sizeof(GraphicsModel::VertexType); 
	offset = 0;
    
	// Set the vertex buffer to active in the input assembler so it can be rendered.
	deviceContext->IASetVertexBuffers(0, 1, &m_vertexBuffer, &stride, &offset);

    // Set the index buffer to active in the input assembler so it can be rendered.
	deviceContext->IASetIndexBuffer(m_indexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // Set the type of primitive that should be rendered from this vertex buffer, in this case triangles.
	deviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

	return;
}